#!/usr/bin/env python3
import re
import socket
import argparse
import select


def get_args():
    """get_args"""
    parser = argparse.ArgumentParser(description="开启指定网站服务")
    parser.add_argument("-p", "--port", type=int, default=8080, help="指定网服务端口")
    parser.add_argument("site", help="指定网站路径")
    return parser.parse_args()


def response_to(client_socket: socket.socket, request, site_path: str):
    # 处理请求
    req_str: str = request.decode("utf-8")
    req_lines = req_str.splitlines()

    ret = re.match(r"[^/]+([^(?| )]*)", req_lines[0])
    file_name = ""
    if ret:
        file_name = ret.group(1)
        if file_name.endswith("/"):
            file_name += "index.html"
        file_name = site_path + file_name
        print("+" * 50 + "\n" + file_name + "\n" + "+" * 50)

    try:
        f_req = open(file_name, "rb")
    except Exception:
        # 生成响应
        # 响应内容
        response_body = "file is not available!"
        # 响应头
        response_header = "HTTP/1.1 404 NOT FOUND\r\n"
        response_header += f"Content-Length:{len(response_body)}\r\n"
        response_header += "\r\n"
        response = (response_header + response_body).encode("utf-8")
        # 发送响应
        client_socket.send(response)
        print("Not found!")

    else:
        html_content = f_req.read()
        f_req.close()
        # 生成响应
        # 响应内容
        response_body = html_content
        # 响应头
        response_header = "HTTP/1.1 200 OK\r\n"
        response_header += f"Content-Length:{len(response_body)}\r\n"
        response_header += "\r\n"
        response = response_header.encode("utf-8") + response_body
        # 发送响应
        client_socket.send(response)

    print(req_str)


def main():
    # 获取命令参数
    args = get_args()
    if args.site:
        if args.site.endswith("/"):
            args.site = args.site[:-1]
    if args.port >= 65535:
        args.port = 8080

    # 创建套接字
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 保证服务器先关闭套接字时，重启程序可以立马重复使用上一次的配置端口
    tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    tcp_socket.setblocking(False)

    # 绑定套接字
    tcp_socket.bind(("", args.port))

    # 监听
    tcp_socket.listen(128)
    print(f"{args.site} 的 http 服务已开启")
    print(f"访问地址: http://127.0.0.1:{args.port}")

    # 创建 epoll
    epo = select.epoll()
    epo.register(tcp_socket.fileno(), select.EPOLLIN)

    client_socket_dict = dict()

    while True:
        fd_event_list = epo.poll()
        for fd, event in fd_event_list:
            if fd == tcp_socket.fileno():
                client_socket, _ = tcp_socket.accept()
                epo.register(client_socket.fileno(), select.EPOLLIN)
                client_socket_dict[client_socket.fileno()] = client_socket
            elif event == select.EPOLLIN:
                request = client_socket_dict[fd].recv(1024)
                if request:
                    response_to(client_socket_dict[fd], request, args.site)
                else:
                    client_socket_dict[fd].close()
                    epo.unregister(fd)
                    del client_socket_dict[fd]

    tcp_socket.close()


if __name__ == "__main__":
    main()
